//
//  RoomController.swift
//  
//
//  Created by Jiang Chencheng on 2024/9/4.
//

import Vapor
import Fluent

struct RoomController: RouteCollection {
    func boot(routes: any Vapor.RoutesBuilder) throws {
        
        let room = routes
            .grouped("room")
            .grouped(SessionToken.authenticator(), SessionToken.guardMiddleware())
        
        room.get("info",use: roomInfo)
        // pair with partner
        room.post("pair", use: pairRoom)
        // exit your room
        room.post("exit", use: exitRoom)
    }
}


// MARK: - Room
extension RoomController {
    
    @Sendable
    func roomInfo(req: Request) async throws -> BizResponse<RoomDTO> {
        let userID = try req.getAuthedUserID()
        let myRoom = try await Room.query(on: req.db, userID: userID)
        return BizResponse(data: myRoom.toDTO())
    }
    
    @Sendable
    func pairRoom(req: Request) async throws -> BizResponse<RoomDTO> {
        
        let userID = try req.getAuthedUserID()
        
        let body = try req.content.decode(PairReq.self)
        
        let myRoom = try await Room.query(on: req.db, userID: userID)
        
        // 不能加入自己的房间
        let isOwner = myRoom.$owner.id == userID && myRoom.$partner.id != nil
        if (isOwner)  { throw BizError.roomOwner }
        
        // 房间里partner如果是自己，就是重复加入
        let isPartner = myRoom.$partner.id == userID
        if (isPartner)  { throw BizError.roomHasJoined }
        
        // 加入其他房间前请先退出原先自己的房间
        if myRoom.$partner.id != nil { throw BizError.myRoomExistPartner }
        
        // 准备加入的用户和用户的房间
        let pairingUser = try await User.query(on: req.db, pairCode: body.code)
        let pairingUserID = try pairingUser.requireID()
        let anotherRoom = try await Room.query(on: req.db, userID: pairingUserID)
        
        // 对方的房间已经有人加入
        let hasPartner = anotherRoom.$partner.id != nil
        if (hasPartner) { throw BizError.roomExistPartner }
        
        // 查询老房间
        let oldRoom = try await findOriginRoom(db: req.db, ownerID: userID, partnerID: pairingUserID)
        
        // 如果有老房间就恢复
        if let oldRoom {
            try await req.db.transaction { transaction in
                try await myRoom.delete(on: transaction)
                try await anotherRoom.delete(on: transaction)
                try await oldRoom.restore(on: transaction)
            }
            return BizResponse(data: oldRoom.toDTO())
        }else {
            // 双方退出原来的自己的房间并加入新的双人房间
            let newRoom = try Room(ownerID:pairingUser.requireID(), partnerID: userID)
            try await req.db.transaction { transaction in
                try await myRoom.delete(on: transaction)
                try await anotherRoom.delete(on: transaction)
                try await newRoom.save(on: transaction)
            }
            return BizResponse(data: newRoom.toDTO())
        }
    }
    
    
    @Sendable
    func exitRoom(req: Request) async throws -> BizResponse<BizVoid> {
        let userID = try req.getAuthedUserID()
        let room = try await Room.query(on: req.db, userID: userID)
        
        let ownerID = room.$owner.id
        guard let partnerID = room.$partner.id else {
            throw BizError.roomExitInvalid
        }
        
        guard let ownerRoom = try await findOriginOwnerRoom(db: req.db, userID: ownerID) else {
            throw BizError.roomRestoreInvalid
        }
        
        guard let partnerRoom = try await findOriginOwnerRoom(db: req.db, userID: partnerID) else {
            throw BizError.roomRestoreInvalid
        }
        
        try await req.db.transaction { transaction in
            try await room.delete(on: transaction)
            try await ownerRoom.restore(on: transaction)
            try await partnerRoom.restore(on: transaction)
        }
        return BizResponse()
    }
}

extension RoomController {
    
    
    /// 查询之前这两个人的房间
    /// - Parameters:
    ///   - db: 数据库
    ///   - ownerID: 用户1
    ///   - partnerID: 用户2
    /// - Returns: 房间
    func findOriginRoom(db: any Database, ownerID: UUID, partnerID: UUID) async throws -> Room? {
        let room = try await Room
            .query(on: db)
            .group(.or) {
                $0.group(.and) {
                    $0.filter(\.$owner.$id == ownerID)
                        .filter(\.$partner.$id == partnerID)
                }.group(.and) {
                    $0.filter(\.$owner.$id == partnerID)
                        .filter(\.$partner.$id == ownerID)
                }
            }
            .withDeleted()
            .first()
        return room
    }
    
    
    
    /// 查询原始自己的房间
    /// - Parameters:
    ///   - db: 数据库
    ///   - userID: 用户
    /// - Returns: 房间
    func findOriginOwnerRoom(db: any Database, userID: UUID) async throws -> Room? {
        let room = try await Room
            .query(on: db)
            .filter(\.$owner.$id == userID)
            .filter(\.$partner.$id == nil)
            .withDeleted()
            .first()
        return room
    }
}
